home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 45
/
Amiga Format CD45 (1999-09)(Future Publishing)(GB)(Track 1 of 2)[!][issue 1999-11].iso
/
-serious-
/
misc
/
mcread
/
original
/
macwrite.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-08-09
|
8KB
|
309 lines
/* mcread: macwrite.c
Copyright (C) 1991, Mike Gleason Jr & NCEMRSoft.
All Rights Reserved. */
#include <stdio.h>
#include <string.h>
#include "mcread.h"
typedef struct {
short type; /* 0-1 */
short unused1[3]; /* 2-7 */
long offset; /* 8-11 */
short len; /* 12-13 */
short unused2; /* 14-15 */
} MacWrite_Paragraph_Info;
#define MACWRITE_45 6
#define MACWRITE_22 3
#define DEFAULT_COMMON " etnroaisdlhcfp"
/* Most commonly occurring characters, MacWrite uses a crude
compression scheme with these. The default uses the American
version. */
#define COMPRESSED_MASK 0x08
char CommonChars[20];
int GNNeedToReadByte = 1; /* for Getn() */
int thrash_macwrite(in, name, dataforklen)
FILE *in;
char *name;
long dataforklen;
{
MacWrite_Paragraph_Info P;
long dataOffset, infoOffset, saved;
register long Seek, StartOffset;
char paragraphStatus;
register int a, b, c, nibble, parIsCompressed;
short version, numparas, curpara;
short bytesInParagraph, bytesOut;
#define CheckReadErr if (ferror(in)) goto ReadErr
#define CheckSeekErr if (Seek) goto SeekErr;
bytesOut = curpara = 0;
(void) strcpy(CommonChars, (char *)DEFAULT_COMMON);
if (dataforklen >= 0)
(void) FindCommon(in, dataforklen);
StartOffset = ftell(in); /* for macbinary files, this will be 128,
otherwise it should be zero. */
version = (short) Getw (in);
CheckReadErr;
if (version != MACWRITE_45) {
if (version == MACWRITE_22)
(void) fprintf (stderr, "%s: macwrite format too old (2.2)\n", name);
else if (dataforklen) {
if (version > MACWRITE_45)
(void) fprintf (stderr, "%s: macwrite format too new (%d)\n", name, version);
else
(void) fprintf (stderr, "%s: macwrite format too old (%d)\n", name, version);
}
return (3);
}
numparas = (short) Getw (in);
CheckReadErr;
Seek = fseek (in, (long) (StartOffset + 264), SEEK_SET);
CheckSeekErr;
/* should now point to the variables for the body text. */
infoOffset = (long) Getl (in);
CheckReadErr;
Seek = fseek (in, (StartOffset + infoOffset), SEEK_SET);
CheckSeekErr;
/* loop through and read all the paragraphs */
while (1) {
P.type = (short) Getw (in); if (ferror(in)) break;
P.unused1[0] = (short) Getw (in); if (ferror(in)) break;
P.unused1[1] = (short) Getw (in); if (ferror(in)) break;
P.unused1[2] = (short) Getw (in); if (ferror(in)) break;
P.offset = (long) Getl (in); if (ferror(in)) break;
P.len = (short) Getw (in); if (ferror(in)) break;
P.unused2 = (short) Getw (in); if (ferror(in)) break;
dataOffset = P.offset & 0x00ffffff; /* lo 3 bytes only */
paragraphStatus = (char) (P.offset >> 24);
if (P.type < 0) { /* a PICT paragraph */
(void) puts ("### picture omitted!");
if (CheckPage())
return (0);
}
if (P.type > 0) { /* a text paragraph */
saved = ftell (in);
Seek = fseek (in, (StartOffset + dataOffset), SEEK_SET);
CheckSeekErr;
bytesInParagraph = (short) Getw (in);
CheckReadErr;
wwInit();
GNNeedToReadByte = 1;
parIsCompressed = paragraphStatus & COMPRESSED_MASK;
for (bytesOut=0; bytesOut<bytesInParagraph; bytesOut++) {
if (parIsCompressed) { /* a compressed paragraph */
nibble = Getn (in);
if (nibble == 0x0f) { /* means that next 2
nibbles form the
next char. */
a = Getn (in);
b = Getn (in);
c = (a << 4) + b;
}
else c = CommonChars[nibble];
} else /* a regular paragraph */
c = getc (in);
if (c == EOF) {
(void) fprintf(stderr, "%s: unexpected end of file.\n", name);
return (4);
}
if (wwPutchar (c & 0x00ff))
return (0); /* user skipped file */
} /* end reading the para */
if (wwFlush())
return (0); /* user skipped file */
Seek = fseek (in, saved, SEEK_SET);
CheckSeekErr;
} /* end text paragraph */
else {
/* it's a ruler, but
who cares? */
}
if (++curpara >= numparas) break;
} /* paragraph loop */
return (0); /* exit success, mon */
SeekErr:
(void) fprintf(stderr, "%s: seek error occurred.\n", name);
return (5);
ReadErr:
(void) fprintf(stderr, "%s: error occurred while trying to read the file.\n", name);
return (6);
} /* thrash_macwrite */
int Getn (f)
FILE *f;
{
static int c;
extern int GNNeedToReadByte;
if (GNNeedToReadByte) {
c = getc(f);
if (c == EOF) return (EOF);
c &= 0x00ff;
GNNeedToReadByte = 0; /* still got the other nibble to use. */
return (c >> 4);
}
GNNeedToReadByte = 1;
return (c & 0x000f);
} /* Getn */
/* This huge mess only accomplishes one thing: read in STR ID 700 from
the resource fork of this macwrite file. What a waste... */
int FindCommon(in, dataForkLen)
FILE *in;
long dataForkLen;
{
#define COMMON_ID 700
register long rezforkstart, typeliststart, Seek;
short numtypes;
register short foundSTR;
struct Oy {
long dataOffset, mapOffset, datalen, maplen;
} rheader;
struct Foo {
long crap[6];
short typelistOffset, namelistOffset;
} rmapheader;
struct Bar {
char type[5];/* really only [4], but I'm not reading in
the whole structure at a time. */
short n; /* number of rsrcs - 1*/
short offset; /* from start of typelist to ref list */
} typeinfo;
struct Grok {
short id, nameoffset;
long dataoffset; /* from start of res data; lo 3 bytes */
long handle;
} refinfo;
rezforkstart = (((128L + dataForkLen) / 128) + 1) * 128;
/* the resource fork starts after the header (128 bytes) and
after the data fork, which is padded to a multiple of 128. */
Seek = fseek (in, rezforkstart, SEEK_SET);
if (Seek) goto done; /* should be at rsrc fork start now */
/* read the resource file header. */
rheader.dataOffset = (long) Getl (in);
if (ferror (in)) goto done;
rheader.mapOffset = (long) Getl (in);
if (ferror (in)) goto done;
rheader.datalen = (long) Getl (in);
if (ferror (in)) goto done;
rheader.maplen = (long) Getl (in);
if (ferror (in)) goto done;
/* read the resource MAP header. */
Seek = fseek (in, (long) (rezforkstart + rheader.mapOffset + 24L), SEEK_SET);
if (Seek) goto done;
rmapheader.typelistOffset = (short) Getw (in); /* 6 craps * 4 bytes = 24L bytes. */
if (ferror (in)) goto done;
/* read the typelist. */
Seek = fseek (in, (long) (rezforkstart + rheader.mapOffset +
rmapheader.typelistOffset), SEEK_SET);
if (Seek) goto done;
typeliststart = ftell (in);
numtypes = (short) Getw (in) + 1; /* rez manager stores (numtypes - 1) ! */
if (ferror(in)) goto done;
foundSTR = 0;
while (!foundSTR && --numtypes >= 0) {
/* read in some info about the next type in the list. */
typeinfo.type[0] = (char) getc (in);
typeinfo.type[1] = (char) getc (in);
typeinfo.type[2] = (char) getc (in);
typeinfo.type[3] = (char) getc (in);
typeinfo.type[4] = '\0';
if (ferror (in)) goto done;
typeinfo.n = (short) Getw (in) + 1; /* rez manager stores (numrsrcs - 1) ! */
if (ferror (in)) goto done;
typeinfo.offset = (short) Getw (in);
if (ferror (in)) goto done;
foundSTR = (strcmp (STR_TYPE, typeinfo.type) == 0);
}
if (!foundSTR) goto done; /* no 'STR '! */
Seek = fseek (in, (long) (typeliststart + typeinfo.offset), SEEK_SET);
if (Seek) goto done;
while (--typeinfo.n >= 0) {
refinfo.id = (short) Getw (in);
if (ferror (in)) goto done;
refinfo.nameoffset = (short) Getw (in);
if (ferror (in)) goto done;
refinfo.dataoffset = (long) Getl (in);
if (ferror (in)) goto done;
refinfo.handle = (long) Getl (in);
if (ferror (in)) goto done;
if (refinfo.id == COMMON_ID) break;
}
if (refinfo.id != COMMON_ID) goto done; /* no CommonChars! */
refinfo.dataoffset &= 0x00ffffff; /* lo 3 bytes for offset */
Seek = fseek (
in,
(long) (rezforkstart + refinfo.dataoffset +
rheader.dataOffset + 5L), /* 4L for the length of the rsrc,
which we already know, and
another 1L for the pascal
string's length byte. */
SEEK_SET);
if (Seek) goto done;
(void) fgets (CommonChars, 18, in);
CommonChars[16] = '\0';
done:
Seek = fseek (in, (long) 128, SEEK_SET);
}
/* eof */